package cn.sanch.basic.service.impl;

import cn.sanch.basic.constant.VerifyConstants;
import cn.sanch.basic.dto.SmsDto;
import cn.sanch.basic.service.IVerifyCodeService;
import cn.sanch.basic.util.BusinessException;
import cn.sanch.basic.util.SmsUtil;
import cn.sanch.basic.util.StrUtils;
import cn.sanch.basic.util.VerifyCodeUtils;
import cn.sanch.user.domain.User;
import cn.sanch.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 *
 * @author sanch37
 * 2022/6/5
 */
@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    /**
     * 注入redis
     */
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    /**
     * 获取手机号注册的图形验证码
     * @param key
     * @return
     */
    @Override
    public String getImageCode(String key) {
        //1.判断key是否为空
        if (key == null) {
            throw new BusinessException("key为空！");
        }
        //2.调用工具类获取四位数的随机数
        String code = StrUtils.getComplexRandomString(4);
        //3.将随机数存入redis里面,5分钟过期
        redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);
        //4.返回随机数的base64位编码后的字符串
        return VerifyCodeUtils.verifyCode(115, 42, code);
    }

    /**
     * 发送手机验证码
     * @param smsDto
     * @return
     */
    @Override
    public void sendPhoneCode(SmsDto smsDto) {
        //获取传递过来的对象里的值
        //手机号
        String phone = smsDto.getPhone();
        //前端输入的验证码
        String imageCode = smsDto.getImageCode();
        //数据库存入的图形验证码key
        String redisImageCodeKey = smsDto.getImageCodeKey();

        //1.空值校验
        if (StringUtils.isEmpty(phone)) {
            throw new BusinessException("手机号不能为空！");
        }
        if (StringUtils.isEmpty(imageCode)) {
            throw new BusinessException("图形验证码不能为空！");
        }
        if (StringUtils.isEmpty(redisImageCodeKey)) {
            throw new BusinessException("请刷新页面重写获取图形验证码！");
        }

        //2.校验图形验证码是否过期
        //获取redis中的验证码
        Object redisImageCode = redisTemplate.opsForValue().get(redisImageCodeKey);
        if (redisImageCode == null) {
            throw new BusinessException("验证码已过期，请重新获取！");
        }

        //3.校验图形验证码是否正确 - equalsIgnoreCase()忽略大小写比较
        if (!redisImageCode.toString().equalsIgnoreCase(imageCode)) {
            throw new BusinessException("图形验证码错误，请重新输入！");
        }

        //4.校验手机号是否被注册
        User user = userMapper.loadByPhone(phone);
        if (user != null) {
            throw new BusinessException("您已注册过，请返回登录界面直接登录！");
        }

        //5.验证手机验证码是否过期   - 约定redis储存手机验证码格式：【register:电话, Smscode:时间戳】
        //获取redis储存的手机验证码
        Object redisSmsCode = redisTemplate.opsForValue().get(VerifyConstants.REGISTER_PREFIX + phone);
        String code = null;

        if (redisSmsCode == null) {
            //等于null就表示第一次发送验证码，redis里面还没有储存，或者redis储存的手机验证码过期了
            //需要重新随机生成6位数的手机验证码
            code = StrUtils.getComplexRandomString(6);
        }else {
            //没有过期
            //reids中有手机验证码，需要校验是否在重发事件内【1分钟】
            //从redis中获取手机验证码，得到【Smscode:时间戳】字符串获取到了进行拆分获取事件戳,转成Long类型
            Long redisTime = Long.parseLong(redisSmsCode.toString().split(":")[1]);
            //获取当前系统时间时间戳[毫秒]
            Long nowTime = System.currentTimeMillis();

            //6.没有过期 - 判断是否过了重发时间
            if ((nowTime - redisTime) < 1*60*1000) {
                //现在系统时间减去手机验证码的重发开始的时间小于1分钟，就表示没有过重发时间的1分钟有效时间
                //就表示用户刷新了页面再次在重发限制时间内再次点了获取
                throw new BusinessException("请勿重复获取验证码！");
            }else {
                //表示过了重复时间但是没过期
                //将之前的储存在redis的手机验证码重新发给用户
                code = redisSmsCode.toString().split(":")[0];
            }

        }

        //7.将手机短信验证码储存到redis中 - 【register:电话, Smscode:时间戳】  3分钟过期时间
        redisTemplate.opsForValue().
                set(VerifyConstants.REGISTER_PREFIX + phone, code + ":" + System.currentTimeMillis(), 3, TimeUnit.MINUTES);

        //8.发送手机验证码
        //SmsUtil.sendSms(phone, "欢迎来到宠物之家，您的验证码为" + code + "，3分钟内有效！");
        System.out.println("欢迎来到宠物之家，您的验证码为" + code + "，3分钟内有效！");

    }

    /**
     * 微信扫码登录绑定手机号发送手机验证码
     * @param smsDto
     */
    @Override
    public void binderSmsCode(SmsDto smsDto) {
        //获取传递过来的对象里的值
        //手机号
        String phone = smsDto.getPhone();

        //1.空值校验
        if (StringUtils.isEmpty(phone)) {
            throw new BusinessException("手机号不能为空！");
        }



        //5.验证手机验证码是否过期   - 约定redis储存手机验证码格式：【register:电话, Smscode:时间戳】
        //获取redis储存的手机验证码
        Object redisSmsCode = redisTemplate.opsForValue().get(VerifyConstants.BINDER_PREFIX + phone);
        String code = null;

        if (redisSmsCode == null) {
            //等于null就表示第一次发送验证码，redis里面还没有储存，或者redis储存的手机验证码过期了
            //需要重新随机生成6位数的手机验证码
            code = StrUtils.getComplexRandomString(6);
        }else {
            //没有过期
            //reids中有手机验证码，需要校验是否在重发事件内【1分钟】
            //从redis中获取手机验证码，得到【Smscode:时间戳】字符串获取到了进行拆分获取事件戳,转成Long类型
            Long redisTime = Long.parseLong(redisSmsCode.toString().split(":")[1]);
            //获取当前系统时间时间戳[毫秒]
            Long nowTime = System.currentTimeMillis();

            //6.没有过期 - 判断是否过了重发时间
            if ((nowTime - redisTime) < 1*60*1000) {
                //现在系统时间减去手机验证码的重发开始的时间小于1分钟，就表示没有过重发时间的1分钟有效时间
                //就表示用户刷新了页面再次在重发限制时间内再次点了获取
                throw new BusinessException("请勿重复获取验证码！");
            }else {
                //表示过了重复时间但是没过期
                //将之前的储存在redis的手机验证码重新发给用户
                code = redisSmsCode.toString().split(":")[0];
            }

        }

        //7.将手机短信验证码储存到redis中 - 【register:电话, Smscode:时间戳】  3分钟过期时间
        redisTemplate.opsForValue().
                set(VerifyConstants.BINDER_PREFIX + phone, code + ":" + System.currentTimeMillis(), 3, TimeUnit.MINUTES);

        //8.发送手机验证码
        //SmsUtil.sendSms(phone, "欢迎来到宠物之家，您的验证码为" + code + "，3分钟内有效！");
        System.out.println("欢迎来到宠物之家，您的验证码为" + code + "，3分钟内有效！");
    }
}
